package com.hmy.infrastructure.service.dingtalk.impl;

import com.hmy.common.exception.ServerException;
import com.hmy.infrastructure.api.bo.request.dingtalk.GetUserRequest;
import com.hmy.infrastructure.api.bo.request.dingtalk.QueryDeptUserRequest;
import com.hmy.infrastructure.api.bo.request.dingtalk.QueryUserRequest;
import com.hmy.infrastructure.api.bo.request.dingtalk.UserBo;
import com.hmy.infrastructure.api.bo.response.dingtalk.dept.DeptIdListResponse;
import com.hmy.infrastructure.api.bo.response.dingtalk.dept.DeptUserDetailResponse;
import com.hmy.infrastructure.api.bo.response.dingtalk.user.UserDetailResponse;
import com.hmy.infrastructure.api.bo.response.dingtalk.user.UserDetailResult;
import com.hmy.infrastructure.common.utils.DingTalkUtil;
import com.hmy.infrastructure.service.dingtalk.IDingTalkUserService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class DingTalkUserService implements IDingTalkUserService {

    private static final Logger log = LoggerFactory.getLogger(DingTalkUserService.class);

    private static final String QUERY_USER_DETAIL_URL = "https://oapi.dingtalk.com/topapi/v2/user/get";

    private static final String QUERY_USER_BY_DEPT_ID = "https://oapi.dingtalk.com/topapi/v2/user/list";

    private static final String QUERY_USER_BY_MOBILE = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private DingTalkUtil dingTalkUtil;

    private final Map<String, String> map = new HashMap<>();
    @Resource
    private DingTalkDeptService dingTalkDeptService;

    public List<UserBo> syncUserData() {
        List<UserDetailResult> result = syncUserData(DingTalkDeptService.ROOT_ID, new ArrayList<>());
        List<UserBo> userList = new ArrayList<>();
        result.forEach(user -> userList.add(convertToUser(user)));
        dingTalkUtil.clearToken();
        map.clear();
        return userList;
    }

    private UserBo convertToUser(UserDetailResult result) {
        UserBo user = new UserBo();
        user.setUserName(result.getName());
        user.setEmail(result.getEmail());
        user.setPhone(result.getMobile());
        user.setRemark(result.getRemark());
        user.setId(result.getUserId());
        user.setAvatar(result.getAvatar());
        user.setDeptIdList(result.getDeptIdList());
        return user;
    }

    /**
     * 同步用户数据
     *
     * @param deptId 部门id
     * @return list 部门数据集合
     */
    public List<UserDetailResult> syncUserData(Long deptId, List<UserDetailResult> list) {
        list.addAll(removeRepeat(getDeptAllUserInfo(deptId)));
        DeptIdListResponse deptDetail = dingTalkDeptService.getDeptIdList(deptId);
        for (Long id : deptDetail.getResult().getDeptIds()) {
            syncUserData(id, list);
        }
        return list;
    }

    /**
     * 去重
     *
     * @param resultList 原始数据集合
     * @return 去重后数据集合
     */
    private List<UserDetailResult> removeRepeat(List<UserDetailResult> resultList) {
        List<UserDetailResult> list = new ArrayList<>();
        for (UserDetailResult result : resultList) {
            if (!map.containsKey(result.getUserId())) {
                list.add(result);
                map.put(result.getUserId(), result.getName());
            }
        }
        return list;
    }

    public UserBo getUserDetail(String userId) {
        log.info("getUserDetail begin  {}", userId);
        UserBo user = null;
        try {
            String url = dingTalkUtil.createUrlWithOutCache(QUERY_USER_DETAIL_URL);
            QueryUserRequest req = new QueryUserRequest();
            req.setUserId(userId);
            log.info("getUserDetail parameter {}, {}", url, req);
            UserDetailResponse res = restTemplate.postForObject(url, req, UserDetailResponse.class);
            if (res != null) {
                log.info("getUserDetail process  {}", res);
                if (res.getResult() != null) {
                    user = convertToUser(res.getResult());
                }
            }
        } catch (Exception e) {
            log.error("Get user Info exception", e);
            throw new ServerException("Get user Info exception");
        }
        log.info("getUserDetail end  {}", user == null ? "user is null" : user);
        return user;
    }

    @Override
    public UserBo getUserInfo(GetUserRequest getUserRequest) {
        log.error("getUserInfo {}", getUserRequest);
        UserBo userBo = null;
        if (StringUtils.isBlank(getUserRequest.getMobile())) {
            return userBo;
        }
        try {
            String url = dingTalkUtil.createUrlWithOutCache(QUERY_USER_BY_MOBILE);
            QueryUserRequest req = new QueryUserRequest();
            req.setMobile(getUserRequest.getMobile());
            log.info("getUserInfo parameter {}, {}", url, req);
            UserDetailResponse res = restTemplate.postForObject(url, req, UserDetailResponse.class);
            if (res != null && res.getResult() != null) {
                userBo = getUserDetail(res.getResult().getUserId());
            } else {
                log.error("getUserInfo res is null");
            }
        } catch (Exception e) {
            log.error("getUserInfo exception ", e);
            return userBo;
        }
        return userBo;
    }


    public List<UserDetailResult> getDeptAllUserInfo(long deptId) {
        DeptUserDetailResponse res;
        List<UserDetailResult> list = new ArrayList<>();
        try {
            String url = dingTalkUtil.createUrl(QUERY_USER_BY_DEPT_ID);
            int cursor = 0;
            QueryDeptUserRequest req = new QueryDeptUserRequest();
            req.setDeptId(deptId);
            req.setCursor(cursor);
            req.setOrderField("modify_desc");
            req.setContainAccessLimit(false);
            res = restTemplate.postForObject(url, req, DeptUserDetailResponse.class);
            if (res == null || res.getResult() == null) {
                return list;
            }
            list.addAll(res.getResult().getList());
            while (res.getResult().isHasMore()) {
                cursor++;
                req.setCursor(cursor);
                res = restTemplate.postForObject(url, req, DeptUserDetailResponse.class);
                if (res != null && res.getResult() != null) {
                    list.addAll(res.getResult().getList());
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            log.error("Get dept user Info exception", e);
            throw new ServerException("Get dept user Info exception");
        }
        return list;
    }

}
